package nfa;

import fa.FARule;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author haoly
 * @title NFATest
 * @date 2025/4/16 14:50
 * @description NFATest
 */
public class NFATest {
    @Test
    void testAccepting() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'b', 1),
                new FARule<>(1, 'b', 2),
                new FARule<>(2, 'a', 3),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 4),
                new FARule<>(3, 'b', 4)
        );
        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFA<Integer> nfa1 = new NFA<>(Set.of(1), Set.of(4), rulebook);
        assertFalse(nfa1.accepting());

        NFA<Integer> nfa2 = new NFA<>(Set.of(1,2,4), Set.of(4), rulebook);
        assertTrue(nfa2.accepting());

    }

    @Test
    void testReadCharacter() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'b', 1),
                new FARule<>(1, 'b', 2),
                new FARule<>(2, 'a', 3),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 4),
                new FARule<>(3, 'b', 4)
        );
        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFA<Integer> nfa = new NFA<>(Set.of(1), Set.of(4), rulebook);
        assertFalse(nfa.accepting());

        nfa.readCharacter('b');
        assertEquals(Set.of(1,2), nfa.getCurrentStates());
        assertFalse(nfa.accepting());

        nfa.readCharacter('a');
        assertEquals(Set.of(1,3), nfa.getCurrentStates());
        assertFalse(nfa.accepting());

        nfa.readCharacter('b');
        assertEquals(Set.of(1,2,4), nfa.getCurrentStates());
        assertTrue(nfa.accepting());
    }

    @Test
    void testReadString() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'b', 1),
                new FARule<>(1, 'b', 2),
                new FARule<>(2, 'a', 3),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'a', 4),
                new FARule<>(3, 'b', 4)
        );
        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFA<Integer> nfa = new NFA<>(Set.of(1), Set.of(4), rulebook);
        assertFalse(nfa.accepting());

        nfa.readString("bbbb");
        assertEquals(Set.of(1,2,3,4), nfa.getCurrentStates());
        assertTrue(nfa.accepting());
    }
}
